﻿
using Xacml.Core.Context;
using Xacml.Core.Policy;
using System;
using System.Collections;
using System.Globalization;

namespace Xacml.Core.Runtime
{
  public class EvaluationContext
  {
    private int _indent = 0;
    private bool _verbose = true;
    private EvaluationEngine _engine;
    private PolicyDocument _policyDocument;
    private ContextDocument _contextDocument;
    private Xacml.Core.Context.ResourceElementReadWrite _currentResource;
    private Policy _currentPolicy;
    private PolicySet _currentPolicySet;
    private Rule _currentRule;
    private bool _isMissingAttribute;
    private bool _processingError;

    public EvaluationEngine Engine
    {
      get
      {
        return this._engine;
      }
    }

    public PolicyDocument PolicyDocument
    {
      get
      {
        return this._policyDocument;
      }
    }

    public ContextDocument ContextDocument
    {
      get
      {
        return this._contextDocument;
      }
    }

    public Xacml.Core.Context.ResourceElementReadWrite CurrentResource
    {
      get
      {
        return this._currentResource;
      }
      set
      {
        this._currentResource = value;
      }
    }

    public bool IsMissingAttribute
    {
      get
      {
        return this._isMissingAttribute;
      }
      set
      {
        this._isMissingAttribute = value;
      }
    }

    public bool ProcessingError
    {
      get
      {
        return this._processingError;
      }
      set
      {
        this._processingError = value;
      }
    }

    public Policy CurrentPolicy
    {
      get
      {
        return this._currentPolicy;
      }
      set
      {
        this._currentPolicy = value;
      }
    }

    public PolicySet CurrentPolicySet
    {
      get
      {
        return this._currentPolicySet;
      }
      set
      {
        this._currentPolicySet = value;
      }
    }

    public Rule CurrentRule
    {
      get
      {
        return this._currentRule;
      }
      set
      {
        this._currentRule = value;
      }
    }

    private EvaluationContext()
    {
    }

    public EvaluationContext(EvaluationEngine engine, PolicyDocument policyDocument, ContextDocument contextDocument)
      : this()
    {
      AttributeCollectionReadWrite attributes = new AttributeCollectionReadWrite();
      foreach (AttributeElementReadWrite attributeElement in (CollectionBase) contextDocument.Request.Resources[0].Attributes)
        attributes.Add(new AttributeElementReadWrite(attributeElement));
      ResourceContentElement resourceContentElement = (ResourceContentElement) null;
      if (contextDocument.Request.Resources[0].ResourceContent != null)
        resourceContentElement = new ResourceContentElement(contextDocument.Request.Resources[0].ResourceContent.XmlDocument, contextDocument.Request.Resources[0].ResourceContent.SchemaVersion);
      this._engine = engine;
      this._policyDocument = policyDocument;
      this._contextDocument = contextDocument;
      this._currentResource = new Xacml.Core.Context.ResourceElementReadWrite((ResourceContentElementReadWrite) resourceContentElement, contextDocument.Request.Resources[0].ResourceScopeValue, attributes, contextDocument.Request.Resources[0].SchemaVersion);
    }

    public void Trace(string message, params object[] parameters)
    {
      if (!this._verbose)
        return;
      Console.Write(new string(' ', this._indent));
      Console.Write(string.Format((IFormatProvider) CultureInfo.InvariantCulture, message, parameters));
      Console.WriteLine();
    }

    public void TraceContextValues()
    {
      if (this.IsMissingAttribute)
		  this.Trace("IsMissingAttribute: {0}", (object)(this.IsMissingAttribute ? true : false));
      if (!this.ProcessingError)
        return;
	  this.Trace("ProcessingError: {0}", (object)(this.ProcessingError ? true : false));
    }

    public void AddIndent()
    {
      ++this._indent;
    }

    public void RemoveIndent()
    {
      --this._indent;
    }
  }
}
